Skip to content

Correct dual-value scope to LP/QP in numerical-optimization API skills#1408

Merged
rapids-bot[bot] merged 3 commits into
NVIDIA:mainfrom
cafzal:claude/stupefied-brahmagupta-00e7f3
Jun 10, 2026
Merged

Correct dual-value scope to LP/QP in numerical-optimization API skills#1408
rapids-bot[bot] merged 3 commits into
NVIDIA:mainfrom
cafzal:claude/stupefied-brahmagupta-00e7f3

Conversation

@cafzal

@cafzal cafzal commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Description

Corrects the dual-value scope in the cuopt-numerical-optimization-api-python and -api-c skills from "LP only" to LP/QP: cuOpt's barrier solver is primal-dual, so a QP with linear constraints returns shadow prices and reduced costs (the "LP only" wording predates the 26.06 QP/barrier work). Documents the boundary — problems with quadratic constraints return no duals (NaN-filled), so the constraints you read duals from must be linear — and adds a short QP-duals example to the Python references.

Verified in source (cuopt_c.h, pdlp/solve.cu) and empirically on a 26.08 nightly (budget dual ≈ 6.667; quadratic constraint → NaN). Follows #1393; companion to #1407 (formulation). Existing lp_duals assets unchanged; validate_skills.sh passes.

Checklist

  • I am familiar with the Contributing Guidelines.
  • Testing
    • New or existing tests cover these changes
    • Added tests
    • Created an issue to follow-up
    • NA
  • Documentation
    • The documentation is up to date with these changes
    • Added new documentation
    • NA

cuOpt's barrier solver is primal-dual (SOCP barrier NVIDIA#1290, general convex
quadratic constraints NVIDIA#1361), so a QP with a quadratic objective and linear
constraints returns dual values and reduced costs — not LP only. The Python
and C API skills still described duals as LP-only, wording that predates the
QP/barrier work (NVIDIA#1183).

- Python SKILL.md: retitle "Getting Dual Values (LP only)" -> "(LP / QP)" and
  rewrite the prose; add a "Reading Duals from a QP" example to
  references/qp_examples.md.
- C SKILL.md: add a "Dual values (LP / QP)" section; add a duals note to
  assets/README.md.

Boundary documented in all four edits: cuOpt returns no dual variables for
problems with quadratic constraints (the dual/reduced-cost arrays come back
filled with NaN), so the constraints whose duals you read must be linear. This
matches docs/cuopt/source/cuopt-c/convex/convex-examples.rst and the QCQP path
in cpp/src/pdlp/solve.cu. Existing lp_duals assets are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: cafzal <cameron.afzal@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

cafzal added a commit to cafzal/cuopt that referenced this pull request Jun 8, 2026
…vior

cpp/src/pdlp/solve.cu (has_quadratic_constraints -> thrust::fill the entire
dual_solution + reduced_cost with quiet_NaN) shows a single quadratic
constraint suppresses duals for the *whole* solve, not just that constraint's
row. Reword "no dual for a quadratic constraint" -> "any quadratic constraint
makes cuOpt return no duals for the whole solve" in Step 3 and the QP eval, for
consistency with PRs NVIDIA#1407 (formulation) and NVIDIA#1408 (api skills, "NaN-filled").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: cafzal <cameron.afzal@gmail.com>
@cafzal cafzal marked this pull request as ready for review June 9, 2026 17:00
@cafzal cafzal requested a review from a team as a code owner June 9, 2026 17:00
@cafzal cafzal requested a review from tmckayus June 9, 2026 17:00
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d944619b-5e09-49e0-b13f-0c6913ca583d

📥 Commits

Reviewing files that changed from the base of the PR and between 98212d5 and 224030d.

📒 Files selected for processing (2)
  • skills/cuopt-numerical-optimization-api-c/SKILL.md
  • skills/cuopt-numerical-optimization-api-python/SKILL.md
✅ Files skipped from review due to trivial changes (1)
  • skills/cuopt-numerical-optimization-api-c/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • skills/cuopt-numerical-optimization-api-python/SKILL.md

📝 Walkthrough

Walkthrough

This PR updates documentation across cuOpt's C and Python API skill guides to clarify when dual values and reduced costs are available. The C API gains a new section documenting cuOptGetDualSolution and cuOptGetReducedCosts behavior. The Python API documentation is expanded from LP-only to cover LP and QP with linear constraints, with both conceptual guidance and example code updated to reflect the expanded scope and NaN behavior.

Changes

Dual Values Availability Documentation

Layer / File(s) Summary
C API dual values documentation
skills/cuopt-numerical-optimization-api-c/SKILL.md
New "Dual values (LP / QP)" section documents cuOptGetDualSolution and cuOptGetReducedCosts for LP and QP, noting that quadratic constraints cause NaN duals and referencing the assets/lp_duals call sequence.
Python API dual values documentation and example
skills/cuopt-numerical-optimization-api-python/SKILL.md
"Getting Dual Values" section expanded from LP-only to LP and QP with linear constraints, clarifying NaN for quadratic constraints and absence of duals in MILP. Python example updated to retrieve and print constraint DualValue under new conditions.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

  • NVIDIA/cuopt#1393: Dual values availability clarification across problem types (LP, MILP, QP) in formulation skill, aligns with this PR's LP/QP dual documentation and NaN behavior guidance for quadratic constraints.

Suggested labels

doc

Suggested reviewers

  • tmckayus
  • rgsl888prabhu
  • mlubin
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: correcting the dual-value scope documentation from LP-only to LP/QP in the numerical-optimization API skills.
Description check ✅ Passed The description is directly related to the changeset, explaining the rationale for expanding dual-value scope from LP to LP/QP, the documented boundary conditions, and verification steps.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/cuopt-numerical-optimization-api-c/SKILL.md`:
- Around line 38-44: Branch has DCO sign-off but lacks the NVSkills bot
signature commit (no commit titled "Attach NVSkills validation signatures"), so
NVSkills CI gating won’t allow merge; ask a maintainer/admin to trigger the
NVSkills validation by commenting `/nvskills-ci` and confirm that the resulting
NVSkills bot signature commit is appended to the branch before merging,
re-checking that a commit from the NVSkills bot is present in the branch
history.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 61de0c4e-d2d6-4469-8bb3-c33bc48d627b

📥 Commits

Reviewing files that changed from the base of the PR and between 2384454 and 98212d5.

📒 Files selected for processing (4)
  • skills/cuopt-numerical-optimization-api-c/SKILL.md
  • skills/cuopt-numerical-optimization-api-c/assets/README.md
  • skills/cuopt-numerical-optimization-api-python/SKILL.md
  • skills/cuopt-numerical-optimization-api-python/references/qp_examples.md

Comment on lines +38 to +44
## Dual values (LP / QP)

`cuOptGetDualSolution` (shadow prices) and `cuOptGetReducedCosts` (reduced costs) return values
for **LP and QP with linear constraints** — the barrier solver is primal-dual, so a quadratic
objective still yields duals. cuOpt returns **no duals for a problem with quadratic constraints**
(the returned arrays are filled with `NaN`). See [assets/lp_duals](assets/lp_duals/) for the call
sequence — it is an LP, but the same calls apply to a QP whose constraints are all linear.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Commits in PR branch missing DCO sign-off =="
git log --format='%H%n%B%n==END==' origin/main..HEAD \
| awk '
  BEGIN { RS="==END==\n"; ORS="\n\n" }
  {
    if ($0 !~ /Signed-off-by:[[:space:]]+/) {
      split($0, lines, "\n")
      print lines[1]
    }
  }
' | sed '/^$/d' || true

echo
echo "== Check for NVSkills signature commit in PR branch =="
git log --oneline origin/main..HEAD | rg -n "Attach NVSkills validation signatures" || true

echo
echo "Expected:"
echo "- No commit hashes printed in DCO section."
echo "- At least one match for 'Attach NVSkills validation signatures' if NVSkills CI has run."

Repository: NVIDIA/cuopt

Length of output: 303


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== DCO check (commit bodies) =="
git log --format='%H%n%B%n==END==' origin/main..HEAD \
| awk '
  BEGIN { RS="==END==\n"; ORS="\n\n" }
  {
    if ($0 !~ /Signed-off-by:[[:space:]]+/) {
      split($0, lines, "\n")
      print lines[1]
    }
  }
' | sed '/^$/d' || true

echo
echo "== NVSkills signature phrase search (commit bodies) =="
git log --format='%H %s%n%B%n---END---\n' origin/main..HEAD \
| rg -n "Attach NVSkills validation signatures" || true

echo
echo "== NVSkills bot presence (commit subjects/bodies) =="
git log --format='%H %s%n%B%n---END---\n' origin/main..HEAD \
| rg -n "nv-nvskill-ci\\[bot\\]|NVSkills CI|NVSkills validation|validation signatures" || true

Repository: NVIDIA/cuopt

Length of output: 198


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Git remotes/branch state =="
git remote -v || true
git branch -a || true
git rev-parse --verify origin/main >/dev/null 2>&1 && echo "origin/main exists" || echo "origin/main missing"

echo
echo "== Commit range size (origin/main..HEAD) =="
git log --oneline origin/main..HEAD --max-count=20 || true
echo
git log --oneline origin/main..HEAD | wc -l

echo
echo "== Any Signed-off-by present in range? (case-insens) =="
git log --format='%H%n%B%n==END==' origin/main..HEAD \
| rg -ni "signed-off-by:" || true

echo
echo "== Any nvskills indicators present in commit messages/bodies? (case-insens) =="
git log --format='%H%n%s%n%B%n==END==' origin/main..HEAD \
| rg -ni "nvskills|nv-nvskill-ci|/nvskills-ci|validation signatures|attach nvskills" || true

echo
echo "== Look for NVSkills attach phrase variants =="
git log --format='%H%n%s%n%B%n==END==' origin/main..HEAD \
| rg -ni "attach.*nvskills|nvskills.*attach|validation.*signature|signature.*validation" || true

Repository: NVIDIA/cuopt

Length of output: 680


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Commits in origin/main..HEAD (subject) =="
git log --format='%H %s' origin/main..HEAD

echo
echo "== Full commit body(s) (to confirm DCO) =="
git log --format='---\ncommit %H\nsubject: %s\nbody:\n%B' origin/main..HEAD

echo
echo "== Check for NVSkills signature phrase across the same range (body+subject) =="
git log --format='%H%n%s%n%B%n==END==' origin/main..HEAD \
| rg -ni "attach nvskills|nvskills|nv-nvskill-ci\\[bot\\]|validation signatures" || true

Repository: NVIDIA/cuopt

Length of output: 1639


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Authors/committers in origin/main..HEAD =="
git log --format='commit %H%n  author: %an <%ae>%n  committer: %cn <%ce>%n  subject: %s%n%n' origin/main..HEAD

echo "== Look for any nvskills/nv-nvskill-ci references by committer/author =="
git log --format='%H%n%an%n%ae%n%cn%n%ce%n%s%n%B==END==' origin/main..HEAD \
| rg -ni "nvskills|nv-nvskill-ci\\[bot\\]|nv-nvskill-ci|/nvskills-ci|validation signatures|attach nvskills" || true

echo "== Show any commits touching skills/ in this range =="
git log --name-only --format='---\ncommit %H %s' origin/main..HEAD -- skills/ | sed -n '1,200p' || true

Repository: NVIDIA/cuopt

Length of output: 8682


Fix NVSkills CI gate for skills/ before merge (DCO present, NVSkills signature missing).

DCO sign-off is present in the updated skills commit. No commit in the branch contains Attach NVSkills validation signatures (or other NVSkills indicators), so NVSkills validation/signature flow still needs to run—ask for /nvskills-ci from a maintainer/admin and re-check that the NVSkills bot signature commit is attached before merging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/cuopt-numerical-optimization-api-c/SKILL.md` around lines 38 - 44,
Branch has DCO sign-off but lacks the NVSkills bot signature commit (no commit
titled "Attach NVSkills validation signatures"), so NVSkills CI gating won’t
allow merge; ask a maintainer/admin to trigger the NVSkills validation by
commenting `/nvskills-ci` and confirm that the resulting NVSkills bot signature
commit is appended to the branch before merging, re-checking that a commit from
the NVSkills bot is present in the branch history.

Source: Coding guidelines

| [milp_production_planning](milp_production_planning/) | MILP | Production planning with resource constraints |
| [mps_solver](mps_solver/) | LP/MILP | Solve from MPS file via `cuOptReadProblem` |

> **Duals:** `lp_duals` is an LP, but `cuOptGetDualSolution` / `cuOptGetReducedCosts` also return

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> **Duals:** `lp_duals` is an LP, but `cuOptGetDualSolution` / `cuOptGetReducedCosts` also return
**Duals:** `lp_duals` is an LP, but `cuOptGetDualSolution` / `cuOptGetReducedCosts` also return

same for other lines as well

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have similar workding in skills, do we need to update in README again?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the note entirely instead of reformatting — it duplicated the Dual values (LP / QP) section now in SKILL.md. Thanks for catching it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call — no need to state it in both. Removed it from the README; the SKILL.md section is the single source.

The Dual values (LP/QP) scope lives in the api-c SKILL.md "Dual values (LP / QP)"
section; the assets/README note restated it. Per review feedback, remove the
duplicate so the skill body is the single source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: cafzal <cameron.afzal@gmail.com>
@cafzal cafzal requested a review from rgsl888prabhu June 9, 2026 19:42
@rgsl888prabhu

Copy link
Copy Markdown
Collaborator

/ok to test 708f5d1

@rgsl888prabhu rgsl888prabhu added non-breaking Introduces a non-breaking change improvement Improves an existing functionality labels Jun 9, 2026

@mlubin mlubin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much of the new content is useful compared with the more minimal change of updating the incorrect "LP only" in skills/cuopt-numerical-optimization-api-python/SKILL.md?


## Dual values (LP / QP)

`cuOptGetDualSolution` (shadow prices) and `cuOptGetReducedCosts` (reduced costs) return values

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to continue my push against "shadow prices". I don't think the parentheticals are necessary here. cuOptGetDualSolution returns duals and cuOptGetReducedCosts returns reduces costs. Readers can look at the function documentation for more information.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Removed. I commit to no more 'shadow prices' too 😆

## Dual values (LP / QP)

`cuOptGetDualSolution` (shadow prices) and `cuOptGetReducedCosts` (reduced costs) return values
for **LP and QP with linear constraints** — the barrier solver is primal-dual, so a quadratic

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to say anything about the barrier solver. The solve method isn't part of the API contract for duals.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved.

problem.addConstraint(x + y + z == 10, name="budget")
problem.solve()

if problem.Status.name in ["Optimal", "PrimalFeasible"]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's safe or correct to check the dual if the status is PrimalFeasible

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved.

## Getting Dual Values (LP only)
## Getting Dual Values (LP / QP)

Shadow prices (`DualValue`) and reduced costs (`ReducedCost`) are returned for **LP and QP** —

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duals and reduced costs (no parentheticals)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved.

- Drop "shadow prices"/"reduced costs" parenthetical glosses (api-c, api-python).
- Remove the barrier-solver mention — the solve method isn't part of the dual
  contract for the API.
- Remove the standalone "Reading Duals from a QP" example; lp_duals already shows
  the call sequence and the SKILL.md sections state it applies to QP (this also
  resolves reading duals on PrimalFeasible status).

Reduces the change to the minimal LP-only -> LP/QP scope correction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: cafzal <cameron.afzal@gmail.com>
cafzal added a commit to cafzal/cuopt that referenced this pull request Jun 9, 2026
…barrier solver"

- Step 5 cross-ref: "defines shadow price ..." -> "covers what duals mean and
  which problem types expose them".
- Step 3 quadratic-constraint note: drop "the barrier solver" (the solve method
  isn't part of the dual contract); keep the second-order-cone constraint form.

Consistent with the trim applied to the api-* skills in NVIDIA#1408.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: cafzal <cameron.afzal@gmail.com>
cafzal added a commit to cafzal/cuopt that referenced this pull request Jun 9, 2026
Replace "shadow prices" with "dual values" in the LP/MILP/QP sensitivity row
and the post-solve note, keeping the decision meaning ("where to invest").
Consistent with the api-* skill trim in NVIDIA#1408.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: cafzal <cameron.afzal@gmail.com>
@rgsl888prabhu

Copy link
Copy Markdown
Collaborator

/ok to test 1048880

@copy-pr-bot

copy-pr-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

/ok to test 1048880

@rgsl888prabhu, there was an error processing your request: E2

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/

@rgsl888prabhu

Copy link
Copy Markdown
Collaborator

/ok to test 1048880

@copy-pr-bot

copy-pr-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

/ok to test 1048880

@rgsl888prabhu, there was an error processing your request: E2

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/

@rgsl888prabhu

Copy link
Copy Markdown
Collaborator

/ok to test 224030d

@rgsl888prabhu

Copy link
Copy Markdown
Collaborator

/merge

@rapids-bot rapids-bot Bot merged commit c58e6fe into NVIDIA:main Jun 10, 2026
43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants